package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author EllieHy
 * @作者 EllieHy
 * @since 2024-05-27
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {
	private final CourseClient courseClient;
	private final CatalogueClient catalogueClient;
	private final LearningRecordMapper recordMapper;
	
	@Override
	@Transactional
	public void addUserLessons(Long userId, List<Long> courseIds) {
		// 远程调用查询课程信息
		List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
		if (CollUtils.isEmpty(courseList)) {
			log.error("课程信息不存在，无法添加到课表");
			return;
		}
		// 封装数据, 设置过期时间 填入userId, courseId
		List<LearningLesson> list = courseList.stream()
				.filter(course -> course.getValidDuration() != null && course.getValidDuration() > 0)
				.map(course -> {
							LearningLesson lesson = new LearningLesson();
							lesson.setCreateTime(LocalDateTime.now());
							lesson.setExpireTime(LocalDateTime.now().plusMonths(course.getValidDuration()));
							lesson.setUserId(userId);
							lesson.setCourseId(course.getId());
							return lesson;
						}
				)
				.collect(Collectors.toCollection(ArrayList::new));
		// 批量保存数据
		this.saveBatch(list);
	}
	
	@Override
	public LearningLessonVO queryMyCurrentLesson() {
		//从请求中获取到用户id
		Long userId = UserContext.getUser();
		// 2.查询正在学习的课程 select * from xx where user_id = #{userId} AND status = 1 order by latest_learn_time limit 1
		LearningLesson lesson = lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
				.orderByDesc(LearningLesson::getLatestLearnTime)
				.last("limit 1")
				.one();
		if (lesson == null) {
			return null;
		}
		// 3.拷贝PO基础属性到VO
		LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
		// 4.查询课程信息
		CourseFullInfoDTO cInfo = courseClient.getCourseInfoById
				(lesson.getCourseId(), false, false);
		if (cInfo == null) {
			throw new BadRequestException("课程信息不存在");
		}
		vo.setCourseName(cInfo.getName());
		vo.setCourseCoverUrl(cInfo.getCoverUrl());
		vo.setSections(cInfo.getSectionNum());
		// 5.统计课表中的课程数量 select count(1) from xxx where user_id = #{userId}
		Integer count = lambdaQuery().eq(LearningLesson::getUserId, userId).count();
		vo.setCourseAmount(count);
		// 6.查询小节信息
		Long latestSectionId = lesson.getLatestSectionId();
		List<CataSimpleInfoDTO> caInfos =
				catalogueClient.batchQueryCatalogue(CollUtils.singletonList(latestSectionId));
		if (CollUtils.isNotEmpty(caInfos)) {
			CataSimpleInfoDTO caInfo = caInfos.get(0);
			vo.setLatestSectionName(caInfo.getName());
			vo.setLatestSectionIndex(caInfo.getCIndex());
		}
		return vo;
	}
	
	/**
	 * @param query 分页参数
	 * @return PageDTO<LearningLessonVO>
	 */
	@Override
	public PageDTO<LearningLessonVO> queryMyLessons(PageQuery query) {
		//1.获取当前登录用户
		Long userId = UserContext.getUser();
		//2.分页查询
		Page<LearningLesson> page = lambdaQuery().eq(LearningLesson::getUserId
				, userId).page(query.toMpPage("latest_learn_time", false));
		List<LearningLesson> records = page.getRecords();
		if (CollUtils.isEmpty(records)) {
			return PageDTO.empty(page);
		}
		//3.查询课程信息
		Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);
		List<LearningLessonVO> list = records.stream().map(r -> {
			// 4.1.循环遍历，把LearningLesson转为VO
			var learningLessonVO = BeanUtils.copyBean(r, LearningLessonVO.class);
			// 4.2.拷贝基础属性到vo
			var courseSimpleInfoDTO = cMap.get(r.getCourseId());
			learningLessonVO.setCourseName(courseSimpleInfoDTO.getName());
			learningLessonVO.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
			learningLessonVO.setSections(courseSimpleInfoDTO.getSectionNum());
			return learningLessonVO;
		}).collect(Collectors.toList());
		//4.封装VO返回
		return PageDTO.of(page, list);
	}
	
	@Override
	public Long isLessonValid(Long courseId) {
		//1.获取当前用户id
		Long userId = UserContext.getUser();
		//2.查询课表learning_lessons 条件是userId,courseId
		LearningLesson lesson = lambdaQuery().eq(LearningLesson::getId,
				userId).eq(LearningLesson::getCourseId, courseId).one();
		if (lesson == null) {
			return null;
		}
		//校验课程是否过期
		LocalDateTime expireTime = lesson.getExpireTime();
		if (expireTime != null && expireTime.isBefore(LocalDateTime.now())) {
			return null;
		}
		return lesson.getId();
	}
	
	@Override
	public LearningLessonVO queryLessonByCourseId(Long courseId) {
		//1.获取当前用户id
		Long userId = UserContext.getUser();
		//2.查询课表learning_lessons 条件是userId,courseId
		LearningLesson lesson = lambdaQuery().eq(LearningLesson::getId,
				userId).eq(LearningLesson::getCourseId, courseId).one();
		if (lesson == null) {
			return null;
		}
		//3.将po转成vo
		return BeanUtils.copyBean(lesson, LearningLessonVO.class);
	}
	
	@Override
	public void deleteCourseFromLesson(Long userId, Long courseId) {
		// 1.获取当前登录用户
		if (userId == null) {
			userId = UserContext.getUser();
		}
		// 2.删除课程
		remove(buildUserIdAndCourseIdWrapper(userId, courseId));
	}
	
	@Override
	public void createLearningPlan(Long courseId, Integer freq) {
		//1.获取当前登录用户id
		Long userId = UserContext.getUser();
		/* 2.查询课表信息 */
		LearningLesson lesson = lambdaQuery()
				.eq(LearningLesson::getId, courseId)
				.eq(LearningLesson::getUserId, userId).one();
		if (lesson == null) {
			throw new BadRequestException("该课程没有加入课表");
		}
		//修改课表
		this.lambdaUpdate()
				.set(LearningLesson::getWeekFreq, freq)
				.set(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
				.eq(LearningLesson::getId, courseId)
				.update();
	}
	
	/**
	 * 分页查询我的学习计划
	 *
	 * @param query 分页参数
	 * @return LearningPlanPageVO
	 */
	@Override
	public LearningPlanPageVO queryMyPlans(PageQuery query) {
		LearningPlanPageVO result = new LearningPlanPageVO();
		//1.获取当前登录用户
		Long userId = UserContext.getUser();
		//TODO 2.查询积分
		//3.查询本周学习计划  根据userId查询, status in(0,1) planStatus=1//代表有学习计划
		QueryWrapper<LearningLesson> wrapper = new QueryWrapper<>();
		wrapper.select("sum(week_freq) as plansTotal ");//查询那些列
		wrapper.eq("user_id", userId);
		wrapper.in("status", LessonStatus.LEARNING, LessonStatus.NOT_BEGIN);
		wrapper.eq("plan_status", PlanStatus.PLAN_RUNNING);
		Map<String, Object> map = this.getMap(wrapper);//这个map键是起的别名,值是妖的数据
		int plansTotal = 0;
		if (map != null && map.get("plansTotal") != null) {
			plansTotal = Integer.parseInt(map.get("plansTotal").toString());
		}
		
		//4.查询本周已经学习的计划总数据
		LocalDate now = LocalDate.now();
		LocalDateTime begin = DateUtils.getWeekBeginTime(now);
		LocalDateTime end = DateUtils.getWeekEndTime(now);
		Integer weekFinished = recordMapper.selectCount(new LambdaQueryWrapper<LearningRecord>()
				.eq(LearningRecord::getUserId, userId)
				.eq(LearningRecord::getFinished, true)
				.gt(LearningRecord::getFinishTime, begin)
				.lt(LearningRecord::getFinishTime, end)
		);
		//5.查询课表数据  learning_lesson  条件:userId status in(0,1) plan_status=1
		Page<LearningLesson> page = this.lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
				.eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
				.page(query.toMpPage("latest_learn_time", false));
		List<LearningLesson> records = page.getRecords();
		if (CollUtils.isEmpty(records)) {
			LearningPlanPageVO vo = new LearningPlanPageVO();
			vo.setWeekFinished(0);
			vo.setWeekTotalPlan(0);
			vo.setWeekPoints(0);
			return vo;
		}
		
		//6.远程查询课程服务 获取课程信息
		Set<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
		List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(cIds);
		if (CollUtils.isEmpty(simpleInfoList)) {
			throw new BadRequestException("课程不存在");
		}
		//转化成map的形式
		Map<Long, CourseSimpleInfoDTO> cMap =
				simpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
		//7.查询学习记录表(本周),当前用户下每一门课下的学习记录
		QueryWrapper<LearningRecord> rWrapper = new QueryWrapper<>();
		rWrapper.select("lesson_id as lessonId", "count(*) as userId");
		rWrapper.eq("user_id", userId).eq("finished", true);
		rWrapper.between("finish_time", begin, end);
		rWrapper.groupBy("lesson_id");
		List<LearningRecord> learningRecords = recordMapper.selectList(rWrapper);
		//map中的key是lessonId,value是当前用户对该课程下已经学习的小节数量
		Map<Long, Long> courseWeekFinishNumMap
				= learningRecords.stream().collect(Collectors.toMap(LearningRecord::getLessonId,
				LearningRecord::getUserId));
		// 8. 封装 VO 返回
		result.setWeekFinished(plansTotal);
		result.setWeekFinished(weekFinished);
		List<LearningPlanVO> voList = records.stream()
				.map(record -> {
					LearningPlanVO learningPlanVO = BeanUtils.copyBean(record, LearningPlanVO.class);
					// 课程信息
					CourseSimpleInfoDTO cInfoDto = cMap.get(record.getCourseId());
					if (cInfoDto != null) {
						learningPlanVO.setCourseName(cInfoDto.getName()); // 课程名称
						learningPlanVO.setSections(cInfoDto.getSectionNum()); // 课程总量
					}
					learningPlanVO.setWeekLearnedSections(
							courseWeekFinishNumMap.getOrDefault(record.getId(), 0L).intValue());
					return learningPlanVO;
				})
				.collect(Collectors.toList());
		return result.pageInfo(page.getTotal(), page.getPages(), voList);
	}
	
	private LambdaQueryWrapper<LearningLesson> buildUserIdAndCourseIdWrapper(Long userId, Long courseId) {
		return new QueryWrapper<LearningLesson>()
				.lambda()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getCourseId, courseId);
	}
	
	
	/**
	 * 调用远程服务查询课程信息
	 *
	 * @param records List<LearningLesson>
	 * @return Map<Long, CourseSimpleInfoDTO> 封装成Map的形式
	 */
	private Map<Long, CourseSimpleInfoDTO> queryCourseSimpleInfoList(List<LearningLesson> records) {
		//3.1.获取课程id集合
		List<Long> courseIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
		//3.2远程查询课程
		List<CourseSimpleInfoDTO> courseList = courseClient.getSimpleInfoList(courseIds);
		if (CollUtils.isEmpty(courseList)) {
			// 课程不存在，无法添加
			throw new BadRequestException("课程信息不存在！");
		}
		//3.3将数据封装到Map中
		return courseList.stream()
				.collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
	}
	
	
}
